using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace MT5Trade.Models.MarketData
{
    /// <summary>
    /// 基于真实市场数据的敞口计算器
    /// </summary>
    public class RealExposureCalculator
    {
        private readonly IMarketDataProvider _dataProvider;
        private readonly GapHedgingStrategy _hedgingStrategy;
        private readonly ILogger<RealExposureCalculator> _logger;

        public RealExposureCalculator(
            IMarketDataProvider dataProvider,
            GapHedgingStrategy hedgingStrategy = null,
            ILogger<RealExposureCalculator> logger = null)
        {
            _dataProvider = dataProvider ?? throw new ArgumentNullException(nameof(dataProvider));
            _hedgingStrategy = hedgingStrategy ?? new GapHedgingStrategy();
            _logger = logger ?? CreateDefaultLogger();
        }

        private static ILogger<RealExposureCalculator> CreateDefaultLogger()
        {
            using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            return loggerFactory.CreateLogger<RealExposureCalculator>();
        }

        /// <summary>
        /// 计算实时敞口
        /// </summary>
        public async Task<ExposureAnalysis> CalculateRealTimeExposureAsync(
            List<Position> positions,
            DateTime asOfDate)
        {
            if (positions == null || !positions.Any())
            {
                return CreateEmptyAnalysis(asOfDate);
            }

            try
            {
                // 获取所有相关品种的最新报价
                var symbols = positions.Select(p => p.Symbol).Distinct().ToList();
                var quotes = await _dataProvider.GetMultipleQuotesAsync(symbols);

                // 计算敞口详情
                var exposureBySymbol = new Dictionary<string, ExposureDetail>();
                decimal totalNominalExposure = 0;
                decimal totalRiskAdjustedExposure = 0;

                foreach (var position in positions)
                {
                    if (!quotes.ContainsKey(position.Symbol))
                    {
                        _logger.LogWarning($"无法获取{position.Symbol}的报价");
                        continue;
                    }

                    var quote = quotes[position.Symbol];
                    var marketValue = (decimal)position.Volume * quote.Close * position.ContractSize;

                    // 获取该品种的波动率
                    var volatility = await _dataProvider.CalculateVolatilityAsync(position.Symbol, 20);

                    // 计算风险调整后的敞口
                    var riskAdjustedExposure = marketValue * (1 + (decimal)volatility.Annualized);

                    // 计算最大潜在损失（基于历史波动率）
                    var maxLoss = marketValue * (decimal)(volatility.Daily * 3); // 3倍标准差

                    // 计算压力测试损失（极端情况）
                    var stressTestLoss = marketValue * (decimal)0.15; // 假设15%的极端下跌

                    exposureBySymbol[position.Symbol] = new ExposureDetail
                    {
                        Symbol = position.Symbol,
                        NominalExposure = marketValue,
                        RiskAdjustedExposure = riskAdjustedExposure,
                        Volatility = volatility,
                        CurrentPrice = quote.Close,
                        PositionSize = position.Volume,
                        Direction = position.Type,
                        MaxLoss = maxLoss,
                        StressTestLoss = stressTestLoss,
                        Beta = await CalculateBetaAsync(position.Symbol)
                    };

                    totalNominalExposure += marketValue;
                    totalRiskAdjustedExposure += riskAdjustedExposure;
                }

                // 识别潜在缺口风险
                var gapRisks = await AnalyzeGapRisksAsync(symbols, asOfDate);

                // 计算对冲建议
                var hedgeRecommendations = await CalculateHedgeRecommendationsAsync(
                    exposureBySymbol, gapRisks);

                // 计算VaR指标
                var (var95, var99, cvar95) = await CalculateVaRMetricsAsync(
                    positions, quotes, asOfDate);

                return new ExposureAnalysis
                {
                    AnalysisDate = asOfDate,
                    TotalNominalExposure = totalNominalExposure,
                    TotalRiskAdjustedExposure = totalRiskAdjustedExposure,
                    ExposureBySymbol = exposureBySymbol,
                    GapRisks = gapRisks,
                    HedgeRecommendations = hedgeRecommendations,
                    RiskScore = CalculateOverallRiskScore(exposureBySymbol, gapRisks),
                    VaR95 = var95,
                    VaR99 = var99,
                    CVaR95 = cvar95
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "计算敞口时发生错误");
                return CreateEmptyAnalysis(asOfDate);
            }
        }

        /// <summary>
        /// 分析缺口风险
        /// </summary>
        private async Task<List<GapEvent>> AnalyzeGapRisksAsync(
            List<string> symbols,
            DateTime asOfDate)
        {
            var allGaps = new List<GapEvent>();

            foreach (var symbol in symbols)
            {
                // 获取最近30天的缺口事件
                var gaps = await _dataProvider.IdentifyGapsAsync(
                    symbol,
                    asOfDate.AddDays(-30),
                    asOfDate,
                    0.005); // 0.5%以上的缺口

                allGaps.AddRange(gaps);
            }

            // 按时间排序并返回最新的缺口
            return allGaps.OrderByDescending(g => g.Time).Take(10).ToList();
        }

        /// <summary>
        /// 计算对冲建议
        /// </summary>
        private async Task<List<HedgeRecommendation>> CalculateHedgeRecommendationsAsync(
            Dictionary<string, ExposureDetail> exposureBySymbol,
            List<GapEvent> gapRisks)
        {
            var recommendations = new List<HedgeRecommendation>();

            foreach (var exposure in exposureBySymbol.Values)
            {
                // 检查是否存在最近的缺口风险
                var recentGaps = gapRisks.Where(g => g.Symbol == exposure.Symbol)
                                         .Take(3).ToList();

                if (recentGaps.Any() || exposure.Volatility.Regime == VolatilityRegime.High)
                {
                    // 需要对冲
                    var hedgeRatio = CalculateOptimalHedgeRatio(exposure, recentGaps);
                    var hedgeSize = exposure.NominalExposure * (decimal)hedgeRatio;

                    recommendations.Add(new HedgeRecommendation
                    {
                        Symbol = exposure.Symbol,
                        HedgeInstrument = DetermineHedgeInstrument(exposure.Symbol),
                        HedgeRatio = hedgeRatio,
                        RecommendedSize = hedgeSize,
                        Rationale = GenerateHedgeRationale(exposure, recentGaps),
                        ExpectedEffectiveness = EstimateHedgeEffectiveness(exposure, hedgeRatio),
                        EstimatedCost = EstimateHedgeCost(hedgeSize, exposure.Volatility)
                    });
                }
            }

            return recommendations;
        }

        /// <summary>
        /// 计算最优对冲比例
        /// </summary>
        private double CalculateOptimalHedgeRatio(
            ExposureDetail exposure,
            List<GapEvent> recentGaps)
        {
            // 基础对冲比例
            double baseRatio = 0.5;

            // 根据波动率调整
            if (exposure.Volatility.Regime == VolatilityRegime.High)
                baseRatio += 0.2;
            else if (exposure.Volatility.Regime == VolatilityRegime.Extreme)
                baseRatio += 0.4;

            // 根据缺口风险调整
            if (recentGaps.Any())
            {
                var avgGapSize = recentGaps.Average(g => (double)g.GapPercentage);
                baseRatio += Math.Min(avgGapSize * 10, 0.3); // 最多增加30%
            }

            // 根据Beta调整
            if (exposure.Beta > 1.2)
                baseRatio += 0.1;

            return Math.Min(baseRatio, 1.0); // 最大100%对冲
        }

        /// <summary>
        /// 确定对冲工具
        /// </summary>
        private string DetermineHedgeInstrument(string symbol)
        {
            // 外汇对冲映射
            if (symbol.Contains("USD"))
                return "DXY"; // 美元指数

            if (symbol.Contains("EUR"))
                return "FXE"; // 欧元ETF

            if (symbol.Contains("GBP"))
                return "FXB"; // 英镑ETF

            if (symbol.Contains("JPY"))
                return "FXY"; // 日元ETF

            // 股票对冲
            if (symbol.Length <= 5 && !symbol.Contains("="))
                return "SPY"; // 默认使用标普500

            return symbol + "_PUT"; // 使用看跌期权
        }

        /// <summary>
        /// 生成对冲理由
        /// </summary>
        private string GenerateHedgeRationale(
            ExposureDetail exposure,
            List<GapEvent> recentGaps)
        {
            var reasons = new List<string>();

            if (exposure.Volatility.Regime == VolatilityRegime.High ||
                exposure.Volatility.Regime == VolatilityRegime.Extreme)
            {
                reasons.Add($"高波动率({exposure.Volatility.Annualized:P0})");
            }

            if (recentGaps.Any())
            {
                reasons.Add($"近期出现{recentGaps.Count}次缺口");
            }

            if (exposure.Beta > 1.2)
            {
                reasons.Add($"高Beta值({exposure.Beta:F2})");
            }

            if (exposure.RiskAdjustedExposure > exposure.NominalExposure * 1.3m)
            {
                reasons.Add("风险调整后敞口偏高");
            }

            return string.Join("；", reasons);
        }

        /// <summary>
        /// 估算对冲有效性
        /// </summary>
        private double EstimateHedgeEffectiveness(ExposureDetail exposure, double hedgeRatio)
        {
            // 基于历史相关性和对冲比例估算
            var baseEffectiveness = 0.6; // 基础有效性

            // 根据对冲比例调整
            baseEffectiveness += hedgeRatio * 0.2;

            // 根据Beta调整
            if (Math.Abs(exposure.Beta - 1.0) < 0.2)
                baseEffectiveness += 0.1;

            return Math.Min(baseEffectiveness, 0.95);
        }

        /// <summary>
        /// 估算对冲成本
        /// </summary>
        private decimal EstimateHedgeCost(decimal hedgeSize, MarketVolatility volatility)
        {
            // 基于期权定价的简化模型
            var impliedVol = (decimal)volatility.Annualized;
            var timeToExpiry = 0.25m; // 3个月

            // Black-Scholes简化估算
            var optionCost = hedgeSize * impliedVol * (decimal)Math.Sqrt((double)timeToExpiry) * 0.4m;

            // 加上交易成本
            var transactionCost = hedgeSize * 0.001m; // 0.1%的交易成本

            return optionCost + transactionCost;
        }

        /// <summary>
        /// 计算整体风险评分
        /// </summary>
        private double CalculateOverallRiskScore(
            Dictionary<string, ExposureDetail> exposureBySymbol,
            List<GapEvent> gapRisks)
        {
            double riskScore = 0;

            // 波动率风险（权重40%）
            var avgVolatility = exposureBySymbol.Values
                .Average(e => e.Volatility.Annualized);
            var volatilityScore = Math.Min(avgVolatility / 0.4, 1.0) * 0.4;

            // 集中度风险（权重30%）
            var totalExposure = exposureBySymbol.Values.Sum(e => e.NominalExposure);
            var maxExposure = exposureBySymbol.Values.Max(e => e.NominalExposure);
            var concentrationScore = (double)(maxExposure / totalExposure) * 0.3;

            // 缺口风险（权重20%）
            var gapScore = Math.Min(gapRisks.Count / 10.0, 1.0) * 0.2;

            // Beta风险（权重10%）
            var avgBeta = exposureBySymbol.Values.Average(e => e.Beta);
            var betaScore = Math.Min(Math.Abs(avgBeta - 1.0), 1.0) * 0.1;

            riskScore = volatilityScore + concentrationScore + gapScore + betaScore;

            return Math.Min(riskScore, 1.0);
        }

        /// <summary>
        /// 计算VaR指标
        /// </summary>
        private async Task<(decimal var95, decimal var99, decimal cvar95)> CalculateVaRMetricsAsync(
            List<Position> positions,
            Dictionary<string, MarketTick> currentPrices,
            DateTime asOfDate)
        {
            // 获取历史收益率数据
            var portfolioReturns = new List<decimal>();

            // 简化：使用单个代表性品种的历史数据
            if (positions.Any())
            {
                var mainSymbol = positions.OrderByDescending(p => p.Volume).First().Symbol;
                var historicalData = await _dataProvider.GetHistoricalDataAsync(
                    mainSymbol,
                    asOfDate.AddDays(-100),
                    asOfDate);

                for (int i = 1; i < historicalData.Count; i++)
                {
                    var dailyReturn = (historicalData[i].Close - historicalData[i - 1].Close)
                                     / historicalData[i - 1].Close;
                    portfolioReturns.Add(dailyReturn);
                }
            }

            if (!portfolioReturns.Any())
            {
                return (0, 0, 0);
            }

            // 计算组合价值
            var portfolioValue = positions.Sum(p =>
            {
                if (currentPrices.ContainsKey(p.Symbol))
                    return (decimal)p.Volume * currentPrices[p.Symbol].Close * p.ContractSize;
                return 0;
            });

            // 排序收益率
            var sortedReturns = portfolioReturns.OrderBy(r => r).ToList();

            // 计算VaR
            var index95 = (int)(sortedReturns.Count * 0.05);
            var index99 = (int)(sortedReturns.Count * 0.01);

            var var95 = portfolioValue * Math.Abs(sortedReturns[index95]);
            var var99 = portfolioValue * Math.Abs(sortedReturns[index99]);

            // 计算CVaR（条件VaR）
            var tailReturns = sortedReturns.Take(index95);
            var cvar95 = portfolioValue * Math.Abs(tailReturns.Average());

            return (var95, var99, cvar95);
        }

        /// <summary>
        /// 计算Beta系数
        /// </summary>
        private async Task<double> CalculateBetaAsync(string symbol)
        {
            try
            {
                // 使用SPY作为市场基准
                var endDate = DateTime.Now;
                var startDate = endDate.AddDays(-60);

                var symbolData = await _dataProvider.GetHistoricalDataAsync(
                    symbol, startDate, endDate);
                var marketData = await _dataProvider.GetHistoricalDataAsync(
                    "SPY", startDate, endDate);

                if (symbolData.Count < 20 || marketData.Count < 20)
                    return 1.0; // 默认Beta

                // 计算收益率
                var symbolReturns = CalculateReturns(symbolData);
                var marketReturns = CalculateReturns(marketData);

                // 计算Beta
                return CalculateBetaFromReturns(symbolReturns, marketReturns);
            }
            catch
            {
                return 1.0; // 发生错误时返回默认Beta
            }
        }

        private List<double> CalculateReturns(List<MarketTick> data)
        {
            var returns = new List<double>();
            for (int i = 1; i < data.Count; i++)
            {
                var ret = (double)((data[i].Close - data[i - 1].Close) / data[i - 1].Close);
                returns.Add(ret);
            }
            return returns;
        }

        private double CalculateBetaFromReturns(List<double> assetReturns, List<double> marketReturns)
        {
            if (assetReturns.Count != marketReturns.Count || assetReturns.Count == 0)
                return 1.0;

            var meanAsset = assetReturns.Average();
            var meanMarket = marketReturns.Average();

            var covariance = assetReturns.Zip(marketReturns,
                (a, m) => (a - meanAsset) * (m - meanMarket)).Average();
            var marketVariance = marketReturns.Average(m => Math.Pow(m - meanMarket, 2));

            if (marketVariance == 0) return 1.0;

            return covariance / marketVariance;
        }

        private ExposureAnalysis CreateEmptyAnalysis(DateTime asOfDate)
        {
            return new ExposureAnalysis
            {
                AnalysisDate = asOfDate,
                TotalNominalExposure = 0,
                TotalRiskAdjustedExposure = 0,
                ExposureBySymbol = new Dictionary<string, ExposureDetail>(),
                GapRisks = new List<GapEvent>(),
                HedgeRecommendations = new List<HedgeRecommendation>(),
                RiskScore = 0
            };
        }
    }
}